
use crate::models::db_connect::get_conn;
use mysql::prelude::Queryable;
use mysql::{from_row, params};
use rocket::serde::json::Json;
use rocket::Error;
use serde::{Deserialize, Serialize};
use std::string::String;


#[derive(Serialize, Deserialize)]
pub struct StudentModel {
    
	pub id:	Option<i32>,
	pub name:	Option<String>,
	pub number:	Option<String>,
}

impl StudentModel {
    pub fn add(param: Json<StudentModel>) -> Result<bool, Error> {
        let mut conn = get_conn();
        conn.exec_iter(
            "INSERT INTO student(id,name,number) VALUES (?,?,?)",
            (
				param.id.clone().unwrap().to_string(),
				param.name.clone().unwrap().to_string(),
				param.number.clone().unwrap().to_string(),

            ),
        )
        .expect("TODO: panic message");

        Ok(true)
    }

    pub fn query(param: Json<StudentModel>) -> Result<Vec<StudentModel>, Error> {
        let mut conn = get_conn();
        let conj = "and";
        let (mut sql_ext, param_values) = StudentModel::concat_cols_make(param, conj);
        if sql_ext.starts_with(conj) {
            sql_ext = sql_ext[conj.len()..].parse().unwrap()
        }
        let pre_sql: String = String::from("SELECT * FROM student where ") + &*sql_ext;
        let stmt = conn.prep(pre_sql);

        let mut students = vec![];
        conn.exec_iter(stmt.unwrap(), param_values)
            .unwrap()
            .for_each(|row| {
                let (id,name,number) = from_row(row.unwrap());
                let query_item = StudentModel {
						id: Some(id),
						name: Some(name),
						number: Some(number),
                    };
                students.push(query_item);
            });

        Ok(students)
    }

    pub fn query_by_pk(id: i32) -> Result<Option<StudentModel>, Error> {
        let mut conn = get_conn();
        let student = conn
            .exec_first(
                "SELECT * FROM student WHERE id = :id",
                params! {
                    "id" => id
                },
            )
            .map(|row| {
                row.map(|(id,name,number)| StudentModel {
						id: Some(id),
						name: Some(name),
						number: Some(number),
                })
            });

        Ok(student.unwrap())
    }

    pub fn update(param: Json<StudentModel>) -> Result<bool, Error> {
        let mut conn = get_conn();
        let conj = ",";
        let pk = param.id.clone().unwrap().to_string();
        let (mut sql_ext, mut param_values) = StudentModel::concat_cols_make(param, conj);
        if sql_ext.starts_with(conj) {
            sql_ext = sql_ext[conj.len()..].parse().unwrap()
        }
        param_values.push(pk);
        let pre_sql: String = String::from("UPDATE student SET ") + &*sql_ext + " WHERE id = ? ";
        let stmt = conn.prep(pre_sql);

        conn.exec_iter(stmt.unwrap(), param_values)
            .expect("TODO: panic message");

        Ok(true)
    }

    pub fn delete(id: i32) -> Result<bool, Error> {
        let mut conn = get_conn();
        conn.exec_iter(
            "DELETE FROM student WHERE id = :id",
            params! {
                "id" => id
            },
        )
        .unwrap();

        Ok(true)
    }

    fn concat_cols_make(param: Json<StudentModel>, conj: &str) -> (String, Vec<String>) {
        let mut s = "".to_string();
        let mut v = vec![];
		if param.id.is_some() {
			s += &*(conj.to_owned() + "id = ?");
			v.push(param.id.clone().unwrap().to_string());
		}
		if param.name.is_some() {
			s += &*(conj.to_owned() + "name = ?");
			v.push(param.name.clone().unwrap().to_string());
		}
		if param.number.is_some() {
			s += &*(conj.to_owned() + "number = ?");
			v.push(param.number.clone().unwrap().to_string());
		}

        (s, v)
    }
}


